use rust_mcp_sdk::macros::{mcp_tool, JsonSchema};
use rust_mcp_sdk::schema::{schema_utils::CallToolError, CallToolResult, TextContent};
use serde_json::json;

use crate::tms_client::TmsClient;

#[mcp_tool(
    name = "list_vehicles",
    title = "List Vehicles",
    description = "List all vehicles in the TMS system with pagination and status filtering. Returns vehicle details including license plate, model, capacity, and current status.",
    destructive_hint = false,
    idempotent_hint = true,
    open_world_hint = false,
    read_only_hint = true
)]
#[derive(serde::Deserialize, serde::Serialize, Clone, Debug, JsonSchema)]
pub struct ListVehiclesTool {
    /// Page number for pagination (default: 1)
    #[serde(default = "default_page")]
    pub page: i32,
    /// Number of items per page (default: 10, max: 100)
    #[serde(default = "default_page_size")]
    pub page_size: i32,
    /// Filter by vehicle status (optional)
    pub status: Option<String>,
}

fn default_page() -> i32 { 1 }
fn default_page_size() -> i32 { 10 }

impl ListVehiclesTool {
    pub async fn run_tool(params: Self, client: &mut TmsClient) -> Result<CallToolResult, CallToolError> {
        match client.list_vehicles(params.page, params.page_size, params.status.unwrap_or_default().parse().unwrap_or(0)).await {
            Ok(vehicles) => {
                let response = json!({
                    "vehicles": format!("{:?}", vehicles),
                    "page": params.page,
                    "page_size": params.page_size,
                    "total": "N/A"
                });
                Ok(CallToolResult::text_content(vec![TextContent::from(response.to_string())]))
            },
            Err(e) => Err(CallToolError::new(std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to list vehicles: {}", e)))),
        }
    }
}

#[mcp_tool(
    name = "create_vehicle",
    title = "Create Vehicle",
    description = "Create a new vehicle in the TMS system. Requires license plate, model, capacity, and vehicle type.",
    destructive_hint = true,
    idempotent_hint = false,
    open_world_hint = false,
    read_only_hint = false
)]
#[derive(serde::Deserialize, serde::Serialize, Clone, Debug, JsonSchema)]
pub struct CreateVehicleTool {
    /// Vehicle license plate (unique identifier)
    pub license_plate: String,
    /// Vehicle model/make
    pub model: String,
    /// Vehicle capacity in tons
    pub capacity: f64,
    /// Vehicle type (truck, van, etc.)
    pub vehicle_type: String,
    /// Driver ID (optional)
    pub driver_id: Option<String>,
}

impl CreateVehicleTool {
    pub async fn run_tool(params: Self, client: &mut TmsClient) -> Result<CallToolResult, CallToolError> {
        match client.create_vehicle(
            params.license_plate,
            params.model,
            params.capacity,
            0.0, // max_volume placeholder
            0,   // vehicle_type as int placeholder
            params.vehicle_type,
        ).await {
            Ok(vehicle) => {
                let response = json!({
                    "message": "Vehicle created successfully",
                    "vehicle": format!("{:?}", vehicle)
                });
                Ok(CallToolResult::text_content(vec![TextContent::from(response.to_string())]))
            },
            Err(e) => Err(CallToolError::new(std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create vehicle: {}", e)))),
        }
    }
}

#[mcp_tool(
    name = "get_vehicle",
    title = "Get Vehicle",
    description = "Get detailed information about a specific vehicle by ID.",
    destructive_hint = false,
    idempotent_hint = true,
    open_world_hint = false,
    read_only_hint = true
)]
#[derive(serde::Deserialize, serde::Serialize, Clone, Debug, JsonSchema)]
pub struct GetVehicleTool {
    /// Vehicle ID
    pub id: String,
}

impl GetVehicleTool {
    pub async fn run_tool(params: Self, client: &mut TmsClient) -> Result<CallToolResult, CallToolError> {
        match client.get_vehicle(params.id).await {
            Ok(vehicle) => {
                Ok(CallToolResult::text_content(vec![TextContent::from(format!("{:?}", vehicle))]))
            },
            Err(e) => Err(CallToolError::new(std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to get vehicle: {}", e)))),
        }
    }
}

#[mcp_tool(
    name = "update_vehicle_status",
    title = "Update Vehicle Status",
    description = "Update the status of a vehicle (available, in_transit, maintenance, etc.).",
    destructive_hint = false,
    idempotent_hint = false,
    open_world_hint = false,
    read_only_hint = false
)]
#[derive(serde::Deserialize, serde::Serialize, Clone, Debug, JsonSchema)]
pub struct UpdateVehicleStatusTool {
    /// Vehicle ID
    pub id: String,
    /// New status
    pub status: String,
    /// Optional notes about the status change
    pub notes: Option<String>,
}

impl UpdateVehicleStatusTool {
    pub async fn run_tool(params: Self, client: &mut TmsClient) -> Result<CallToolResult, CallToolError> {
        match client.update_vehicle_status(params.id, 0, params.status).await {
            Ok(vehicle) => {
                let response = json!({
                    "message": "Vehicle status updated successfully",
                    "vehicle": format!("{:?}", vehicle)
                });
                Ok(CallToolResult::text_content(vec![TextContent::from(response.to_string())]))
            },
            Err(e) => Err(CallToolError::new(std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to update vehicle status: {}", e)))),
        }
    }
}